#include "Socket.hpp"
#include "Protocol.hpp"
#include "Factory.hpp"
using namespace socket_ns;

void Useage(const std::string &str)
{
    std::cout << "Useage:\n\t" << str << " ip port \n";
    exit(USE_ERR);
}

enum class Status
{
    NEW,          // 新创建
    CONNECTING,   // 正在连接的状态
    CONNECTED,    // 连接或重连成功
    DISCONNECTED, // 重连失败
    CLOSED        // 连接失败，重连失败，无法连接
};

// 断线重连
class ClientConnection
{
    static const int retry_time = 1;
    static const int retry_cnts = 5;

public:
    ClientConnection(uint16_t port, const std::string &ip)
        : _fd(defaultFd), _addr(port, ip), _stat(Status::NEW), _retry_time(retry_time), _retry_cnts(retry_cnts)
    {
    }
    void Connect()
    {
        _fd = ::socket(AF_INET, SOCK_STREAM, 0);
        if (_fd < 0)
        {
            std::cout << "socket create fail\n";
            exit(1);
        }
        std::cout << "socket create success\n";

        struct sockaddr_in server = _addr.Addr();
        int n = ::connect(_fd, reinterpret_cast<struct sockaddr *>(&server), sizeof server);
        if (n < 0)
        {
            std::cout << "connect fail\n";
            DisConnect();
            _stat = Status::DISCONNECTED;
            return;
        }
        _stat = Status::CONNECTED;
        std::cout << "connect success\n";
    }
    void ReConnect()
    {
        _stat = Status::CONNECTING;
        int count = 0;
        while (count < _retry_cnts)
        {
            Connect();
            if (_stat == Status::CONNECTED)
                return;
            sleep(_retry_time);
            count++;
            std::cout << "断线重连次数 ： " << count << ", 最大上限 ：" << _retry_cnts << std::endl;
        }
        _stat = Status::CLOSED;
    }
    void Process()
    {
        std::string inbuffer;
        while(true)
        {
            sleep(1);
            // 1.生成请求
            Request req = Factory::GetRandomRequest();

            // 2. 序列化
            std::string out;
            req.Serialize(out);
            // std::cout << "message : " << out << std::endl;

            // 3. 添加包头
            out = EnCode(out);
            // std::cout << "encode message : " << out << std::endl;

            // 4. 发送
            ::send(_fd, out.c_str(), out.size(), 0);

            // 5.接受
            char buff[1024];
            ssize_t n = ::recv(_fd, buff, sizeof(buff) - 1, 0);
            if (n > 0)
            {
                buff[n] = 0;
                inbuffer += buff;
            }
            else if (n == 0)
            {
                _stat = Status::DISCONNECTED;
                break;
            }
            else
            {
                _stat = Status::CLOSED;
                break;
            }

            // 6. 判断是否是一个完整的应答
            std::string result;
            while ((result = DeCode(inbuffer)) != "")
            {
                // 7.反序列化
                Response res = Factory::CreateResponse();
                res.DeSerialize(result);

                std::cout << "result : " << res._result << ", code : " << res._code << std::endl;
            }
        }
    }
    void DisConnect()
    {
        if (_fd > -1)
        {
            ::close(_fd);
            _stat = Status::CLOSED;
            _fd = defaultFd;
        }
    }
    Status GetStat()
    {
        return _stat;
    }
    ~ClientConnection()
    {
        DisConnect();
    }

private:
    int _fd;
    InetAddr _addr;
    Status _stat;
    int _retry_time;
    int _retry_cnts;
};

class TcpClient
{
public:
    TcpClient(uint16_t port, const std::string &ip)
        : _con(port, ip)
    {
    }
    void Excute()
    {
        while (true)
        {
            switch (_con.GetStat())
            {
            case Status::NEW:
                _con.Connect();
                break;
            case Status::CONNECTED:
                _con.Process();
                break;
            case Status::DISCONNECTED:
                _con.ReConnect();
                break;
            case Status::CLOSED:
                _con.DisConnect();
                return;
            default:
                break;
            }
        }
    }
    ~TcpClient()
    {
    }

private:
    ClientConnection _con;
};

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Useage(argv[0]);
    }

    srand(time(nullptr));
    std::string ip = argv[1];
    uint16_t port = std::stoi(argv[2]);
    TcpClient tcvr(port, ip);
    tcvr.Excute();

    return 0;
}

// int main(int argc, char *argv[])
// {
//     if (argc != 3)
//     {
//         Useage(argv[0]);
//     }

//     srand(time(nullptr));
//     std::string ip = argv[1];
//     uint16_t port = std::stoi(argv[2]);

//     std::unique_ptr<Socket> csptr = std::make_unique<TcpSocket>();
//     InetAddr server(port, ip);
//     csptr->BuildClientSock(server);

//     std::string inbuffer;
//     while (true)
//     {
//         sleep(1);
//         // 1.生成请求
//         Request req = Factory::GetRandomRequest();

//         // 2. 序列化
//         std::string out;
//         req.Serialize(out);
//         std::cout << "message : " << out << std::endl;

//         // 3. 添加包头
//         out = EnCode(out);
//         // std::cout << "encode message : " << out << std::endl;

//         // 4. 发送
//         csptr->Send(out);

//         // 5.接受
//         csptr->Recv(inbuffer);

//         // 6. 判断是否是一个完整的应答
//         std::string result;
//         while ((result = DeCode(inbuffer)) != "")
//         {
//             // 7.反序列化
//             Response res = Factory::CreateResponse();
//             res.DeSerialize(result);

//             std::cout << "result : " << res._result << ", code : " << res._code << std::endl;
//         }
//     }

//     return 0;
// }